/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version 1.1 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain
 * a copy of the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 *
 * The Original Code is [Open Source Virtual Machine.]
 *
 * The Initial Developer of the Original Code is Adobe System Incorporated.  Portions created
 * by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
 * Reserved.
 *
 * Contributor(s): Adobe AS3 Team
 *                 Andreas Gal <gal@mozilla.com>
 *
 * Alternatively, the contents of this file may be used under the terms of either the GNU
 * General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
 * License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
 * LGPL are applicable instead of those above. If you wish to allow use of your version of this
 * file only under the terms of either the GPL or the LGPL, and not to allow others to use your
 * version of this file under the terms of the MPL, indicate your decision by deleting provisions
 * above and replace them with the notice and other provisions required by the GPL or the
 * LGPL. If you do not delete the provisions above, a recipient may use your version of this file
 * under the terms of any one of the MPL, the GPL or the LGPL.
 *
 ***** END LICENSE BLOCK ***** */

/*
 *  nanojit-support.cpp
 *  joosVM
 *
 *  Created by Smári Waage on 11.11.2009.
 *
 */

#include "nanojit-support.h"

static avmplus::AvmCore s_core = avmplus::AvmCore();
static avmplus::AvmCore* core = &s_core;

/* Allocator SPI implementation. */

void*
nanojit::Allocator::allocChunk(size_t nbytes)
{
    VMAllocator *vma = (VMAllocator*)this;
    JASSERT(!vma->outOfMemory());
    void *p = calloc(1, nbytes);
    if (!p) {
        JASSERT(nbytes < sizeof(vma->mReserve));
        vma->mOutOfMemory = true;
        p = (void*) &vma->mReserve[0];
    }
    vma->mSize += nbytes;
    return p;
}

void
nanojit::Allocator::freeChunk(void *p) {
    VMAllocator *vma = (VMAllocator*)this;
    if (p != &vma->mReserve[0])
        free(p);
}

void
nanojit::Allocator::postReset() {
    VMAllocator *vma = (VMAllocator*)this;
    vma->mOutOfMemory = false;
    vma->mSize = 0;
}


void JSTraceMonitor::flush(){
	// AUDIT(cacheFlushed);
	
    // recover profiling data from expiring Fragments
    verbose_only(
				 for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) {
				 for (VMFragment *f = vmfragments[i]; f; f = f->next) {
				 JS_ASSERT(f->root == f);
				 for (VMFragment *p = f; p; p = p->peer)
				 js_FragProfiling_FragFinalizer(p, this);
				 }
				 }
				 )
	
    verbose_only(
				 for (Seq<Fragment*>* f = branches; f; f = f->tail)
				 js_FragProfiling_FragFinalizer(f->head, this);
				 )
	
    //frameCache->reset();
    dataAlloc->reset();
    traceAlloc->reset();
    codeAlloc->reset();
	
    Allocator& alloc = *dataAlloc;
	/*
	 for (size_t i = 0; i < MONITOR_N_GLOBAL_STATES; ++i) {
	 globalStates[i].globalShape = -1;
	 globalStates[i].globalSlots = new (alloc) SlotList(&alloc);
	 }*/
	
    assembler = new (alloc) Assembler(*codeAlloc, alloc, core, NULL);//&js_LogController);
    lirbuf = new (alloc) LirBuffer(*tempAlloc);
    reLirBuf = new (alloc) LirBuffer(*reTempAlloc);
    verbose_only( branches = NULL; )
	
#ifdef DEBUG
    labels = new (alloc) LabelMap(alloc, &js_LogController);
    reLirBuf->names =
    lirbuf->names = new (alloc) LirNameMap(alloc, labels);
#endif
	
	// memset(&vmfragments[0], 0, FRAGMENT_TABLE_SIZE * sizeof(VMFragment*));
    //reFragments = new (alloc) REHashMap(alloc);
	
    //needFlush = JS_FALSE;
}



static bool CheckForSSE2() {
    char *c = getenv("X86_FORCE_SSE2");
    if (c)
        return (!strcmp(c, "true") ||
                !strcmp(c, "1") ||
                !strcmp(c, "yes"));
	
    int features = 0;
#if defined _MSC_VER
    __asm
    {
        pushad
        mov eax, 1
        cpuid
        mov features, edx
        popad
    }
#elif defined __GNUC__
    asm("xchg %%esi, %%ebx\n" /* we can't clobber ebx on gcc (PIC register) */
        "mov $0x01, %%eax\n"
        "cpuid\n"
        "mov %%edx, %0\n"
        "xchg %%esi, %%ebx\n"
        : "=m" (features)
        : /* We have no inputs */
        : "%eax", "%esi", "%ecx", "%edx"
		);
#elif defined __SUNPRO_C || defined __SUNPRO_CC
    asm("push %%ebx\n"
        "mov $0x01, %%eax\n"
        "cpuid\n"
        "pop %%ebx\n"
        : "=d" (features)
        : /* We have no inputs */
        : "%eax", "%ecx"
		);
#endif
    return (features & (1<<26)) != 0;
}





void TraceJIT::InitJIT(JSTraceMonitor *tm){
	// memset(&js_LogController, 0, sizeof(js_LogController));
#if defined NANOJIT_IA32
	avmplus::AvmCore::config.use_cmov =
	avmplus::AvmCore::config.sse2 = CheckForSSE2();
	avmplus::AvmCore::config.fixed_esp = true;
#endif
#if defined NANOJIT_ARM
	
	js_disable_debugger_exceptions();
	
	bool            arm_vfp     = js_arm_check_vfp();
	bool            arm_thumb   = js_arm_check_thumb();
	bool            arm_thumb2  = js_arm_check_thumb2();
	unsigned int    arm_arch    = js_arm_check_arch();
	
	js_enable_debugger_exceptions();
	
	avmplus::AvmCore::config.vfp        = arm_vfp;
	avmplus::AvmCore::config.soft_float = !arm_vfp;
	avmplus::AvmCore::config.thumb      = arm_thumb;
	avmplus::AvmCore::config.thumb2     = arm_thumb2;
	avmplus::AvmCore::config.arch       = arm_arch;
	avmplus::AvmCore::config.tree_opt = true;
	// Sanity-check the configuration detection.
	//  * We don't understand architectures prior to ARMv4.
	JS_ASSERT(arm_arch >= 4);
	//  * All architectures support Thumb with the possible exception of ARMv4.
	JS_ASSERT((arm_thumb) || (arm_arch == 4));
	//  * Only ARMv6T2 and ARMv7(+) support Thumb2, but ARMv6 does not.
	JS_ASSERT((arm_thumb2) || (arm_arch <= 6));
	//  * All architectures that support Thumb2 also support Thumb.
	JS_ASSERT((arm_thumb2 && arm_thumb) || (!arm_thumb2));
#endif
	
	
    /* Set the default size for the code cache to 16MB. */
    tm->maxCodeCacheBytes = 16000000;// M;
	/*
	 if (!tm->recordAttempts.ops) {
	 JS_DHashTableInit(&tm->recordAttempts, JS_DHashGetStubOps(),
	 NULL, sizeof(PCHashEntry),
	 JS_DHASH_DEFAULT_CAPACITY(PC_HASH_COUNT));
	 }
	 */
    //JASSERT(!tm->dataAlloc && !tm->traceAlloc && !tm->codeAlloc);
    tm->dataAlloc = new VMAllocator();
    tm->traceAlloc = new VMAllocator();
    tm->tempAlloc = new VMAllocator();
    tm->reTempAlloc = new VMAllocator();
    tm->codeAlloc = new CodeAlloc();
	// tm->frameCache = new FrameInfoCache(tm->dataAlloc);
    tm->flush();
    verbose_only( tm->branches = NULL; )
	
	// JS_ASSERT(!tm->reservedDoublePool);
	// tm->reservedDoublePoolPtr = tm->reservedDoublePool = new jsval[MAX_NATIVE_STACK_SLOTS];
	
#if !defined XP_WIN
    debug_only(memset(&jitstats, 0, sizeof(jitstats)));
#endif
	
#ifdef JS_JIT_SPEW
    /* Architecture properties used by test cases. */
    jitstats.archIsIA32 = 0;
    jitstats.archIs64BIT = 0;
    jitstats.archIsARM = 0;
    jitstats.archIsSPARC = 0;
    jitstats.archIsPPC = 0;
#if defined NANOJIT_IA32
    jitstats.archIsIA32 = 1;
#endif
#if defined NANOJIT_64BIT
    jitstats.archIs64BIT = 1;
#endif
#if defined NANOJIT_ARM
    jitstats.archIsARM = 1;
#endif
#if defined NANOJIT_SPARC
    jitstats.archIsSPARC = 1;
#endif
#if defined NANOJIT_PPC
    jitstats.archIsPPC = 1;
#endif
#if defined NANOJIT_X64
    jitstats.archIsAMD64 = 1;
#endif
#endif
}

